package org.example.gateway.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import io.jsonwebtoken.Claims;
import org.example.core.constant.SecurityConstants;
import org.example.core.constant.TokenConstants;
import org.example.core.utils.JwtUtils;
import org.example.core.utils.R;
import org.example.gateway.helper.RequestHelper;
import org.example.gateway.properties.FrontIgnoreWhiteProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;

/**
 * @author 小杰_cc
 * @version 1.0
 */

/**
 * 前台过滤器
 */
@Component
@Order(2)
public class FrontAuthorizeFilter implements GlobalFilter {

    @Autowired
    private FrontIgnoreWhiteProperties frontIgnoreWhite;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // 获取request
        ServerHttpRequest request = exchange.getRequest();

        // 直接放行的请求
        String url = request.getURI().getPath();
        // 跳过不需要验证的路径
        if (RequestHelper.checkUrl(url, frontIgnoreWhite.getWhites())){
            return chain.filter(exchange);
        }

        // 需要验证的路径,需要token
        ServerHttpResponse response = exchange.getResponse();
        String authentication = request.getHeaders().getFirst(TokenConstants.AUTHENTICATION);
        // 判断是否存在
        if(StrUtil.isBlank(authentication)){
            return unAuthorizeResponse(response, HttpStatus.UNAUTHORIZED.value(),"令牌不能为空");
        }
        // 解析令牌
        Claims claims = JwtUtils.getMemberClaims(authentication);
        if (claims == null){
            return unAuthorizeResponse(response,HttpStatus.UNAUTHORIZED.value(),"令牌认证失败");
        }

        // 获取token内的数据
        String memberId = JwtUtils.getMemberId(claims);
        String memberName = JwtUtils.getMemberName(claims);
        if (StrUtil.isBlank(memberId) || StrUtil.isBlank(memberName)){
            return unAuthorizeResponse(response,HttpStatus.UNAUTHORIZED.value(), "令牌解析失败");
        }
        // 认证成功。设置添加数据到请求头
        ServerHttpRequest.Builder mutate = request.mutate();
        addHeader(mutate,TokenConstants.MEMBER_ID,memberId);
        addHeader(mutate,TokenConstants.MEMBER_NAME,memberName);
        // 内部请求来源参数清除
        removeHeader(mutate);
        return chain.filter(exchange.mutate().request(mutate.build()).build());
    }

    // 添加请求头
    private void addHeader(ServerHttpRequest.Builder mutate, String name, Object value) {
        if (value == null) {
            return;
        }
        String valueStr = value.toString();
        String valueEncode = URLEncoder.encode(valueStr, StandardCharsets.UTF_8);
        mutate.header(name, valueEncode);
    }

    private void removeHeader(ServerHttpRequest.Builder mutate) {
        mutate.headers(httpHeaders -> httpHeaders.remove(SecurityConstants.FROM_SOURCE)).build();
    }

    // 认证失败的返回
    private Mono<Void>  unAuthorizeResponse(ServerHttpResponse response, int code, String msg) {
        response.setStatusCode(HttpStatus.OK);
        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        DataBuffer buffer = new DefaultDataBufferFactory().wrap(JSONUtil.toJsonStr(R.error(code,msg)).getBytes());
        return response.writeWith(Mono.just(buffer));
    }
}
